package com.wispx.gateway.core.filter;

import cn.hutool.core.collection.ConcurrentHashSet;
import com.wispx.gateway.config.manager.DynamicConfigManager;
import com.wispx.gateway.config.manager.RouteListener;
import com.wispx.gateway.config.pojo.RouteDefinition;
import com.wispx.gateway.core.context.GatewayContext;
import lombok.extern.slf4j.Slf4j;

import java.util.*;
import java.util.concurrent.ConcurrentHashMap;

import static com.wispx.gateway.common.constant.FilterConstant.*;

@Slf4j
public class FilterChainFactory {

    private static final Map<String/* filter唯一标识 */, Filter> filterMap = new HashMap<>();
    private static final Map<String/* 服务名 */, FilterChain> filterChainMap = new ConcurrentHashMap<>();
    private static final Set<String/* 服务名 */> addedListener = new ConcurrentHashSet<>();

    static {
        ServiceLoader<Filter> filters = ServiceLoader.load(Filter.class);
        for (Filter filter : filters) {
            if (filter != null) {
                filterMap.put(filter.mark(), filter);
                log.info("success load filter: {}", filter.mark());
            }
        }
    }

    public static void buildFilterChain(GatewayContext ctx) {
        RouteDefinition route = ctx.getRouteDefinition();
        FilterChain chain = filterChainMap.computeIfAbsent(route.getServiceName(), serviceName -> {
            FilterChain filterChain = new FilterChain();
            addPreFilter(filterChain);
            addFilter(filterChain, route.getFilterConfigs());
            addPostFilter(filterChain);
            filterChain.sort();
            if (!addedListener.contains(serviceName)) { // 确保只添加一次监听器
                DynamicConfigManager.getInstance().addRouteListener(serviceName, new RouteListener() {
                    @Override
                    public void routeOnChange(RouteDefinition route) {
                        filterChainMap.remove(serviceName);
                    }
                });
                addedListener.add(serviceName);
            }
            return filterChain;
        });
        ctx.setFilterChain(chain);
    }

    private static void addPreFilter(FilterChain filterChain) { // 添加固定的前置过滤器
        addFilterIfPresent(filterChain, CORS_FILTER_NAME);
        addFilterIfPresent(filterChain, FLOW_FILTER_NAME);
        addFilterIfPresent(filterChain, GRAY_FILTER_NAME);
        addFilterIfPresent(filterChain, LOAD_BALANCE_FILTER_NAME);
    }

    private static void addFilter(FilterChain filterChain, Set<RouteDefinition.FilterConfig> filters) {
        if (filters == null || filters.isEmpty()) {
            return;
        }
        for (RouteDefinition.FilterConfig filterConfig : filters) {
            if (!addFilterIfPresent(filterChain, filterConfig.getName())) {
                log.warn("add filter {} fail to filterChain {}", filterConfig.getName(), filterChain);
            }
        }
    }


    private static void addPostFilter(FilterChain filterChain) { // 添加固定的后置过滤器
        addFilterIfPresent(filterChain, ROUTE_FILTER_NAME);
    }

    private static boolean addFilterIfPresent(FilterChain filterChain, String filterName) {
        Filter filter = filterMap.get(filterName);
        if (filter != null) {
            filterChain.add(filter);
            return true;
        }
        return false;
    }

}
